package cn.tedu.knows.faq.interceptor;

import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Resource
    private RestTemplate restTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获得请求中包含的jwt
        String token = request.getParameter("accessToken");

        //利用auth授权服务器功能解析token令牌
        //获得令牌中包含的信息
        String url = "http://auth-service/oauth/check_token?token={1}";
        Map<String, Object> map = restTemplate.getForObject(url, Map.class, token);

        //Map 会自动解析JSON格式中各种信息
        //而我们只需要user_name和authorities
        //接受用户名
        String username = map.get("user_name").toString();

        //接收所有auth,使用List<String>来接收
        List<String> list = (List<String>) map.get("authorities");

        //获得用户必要信息,保存到Spring-Security中
        //因为保存到Spring-Security是框架提供的功能,
        //所以方式时固定的
        String[] auth = list.toArray(new String[0]);

        UserDetails userDetails = User.builder()
                .username(username)
                .password("")
                .authorities(auth)
                .build();
        //我们已经获得了用户详情对象
        //下面要将他保存在Spring-Security框架中
        //以便在其他控制器中获取
        //Spring-Security给定了固定的方式来实现这个功能
        PreAuthenticatedAuthenticationToken authenticationToken
                = new PreAuthenticatedAuthenticationToken(
                userDetails
                , userDetails.getPassword()
                , AuthorityUtils.createAuthorityList(auth));

        //设置关联当前请求才能保存到Spring-Security
        authenticationToken.setDetails(
                new WebAuthenticationDetails(request)
        );

        //将当前用户信息保存到Spring-Security上下文对象
        //上下文对象就是指保存用户信息的容器
        SecurityContextHolder.getContext()
                .setAuthentication(authenticationToken);

        return true;
    }
}
